﻿using System;
using System.Drawing;
using System.Linq;
using RoboRallyAPI;

namespace SimpleAI
{
	/// <summary>
	/// A very simplistic implementation of the AI. This AI is used if we have less than 8 players.
	/// </summary>
	public class SimplePlayer : IPlayer
	{
		private readonly Random rand = new Random();

		private readonly string name;

		/// <summary>
		/// Create the object.
		/// </summary>
		/// <param name="name">The name for this AI player.</param>
		public SimplePlayer(string name)
		{
			this.name = name;
		}

		/// <summary>
		/// The name of the player.
		/// </summary>
		public string Name
		{
			get { return name; }
		}

		/// <summary>
		/// The avatar of the player. Must be 32 x 32.
		/// </summary>
		public Image Avatar
		{
			get { return null; }
		}

		/// <summary>
		/// Called when your robot must be placed on the board. This is called at the start of the game and each time your robot dies.
		/// </summary>
		/// <param name="map">The game map. There will be no units on this map.</param>
		/// <param name="you">Your player object.</param>
		/// <param name="robotStart">The position(s) on the map where you can place your robot. This will be a single point unless another robot is on your archive point.</param>
		/// <returns>Where to place your unit (location and direction.</returns>
		public PlayerSetup Setup(GameMap map, Player you, Point[] robotStart)
		{
			return new PlayerSetup(robotStart[0], MapSquare.DIRECTION.NORTH);
		}

		/// <summary>
		/// Called each time the system needs another turn. If you do not return a valid turn, the game will randomly move one of your units.
		/// This call must return in under 1 second. If it has not returned in 1 second the call will be aborted and a random move will be assigned.
		/// </summary>
		/// <param name="map">The game map with all units on it.</param>
		/// <param name="you">Your player object. This is created for each call.</param>
		/// <param name="allPlayers">All players including you. This is created for each call.</param>
		/// <param name="cards">The cards you get to pick from. This does not include locked cards.</param>
		/// <returns>Your requested turn.</returns>
		public PlayerTurn Turn(GameMap map, Player you, Player[] allPlayers, Card[] cards)
		{

			// if hurt bad, consider power down
			bool powerDown = false;
			if ((you.Damage > 5) && (rand.Next(3) == 0))
				powerDown = true;

			// get 40 sets, pick the one that's closest to the flag
			Card[] best = null;
			int bestDiff = int.MaxValue;
			int okDiff = rand.Next(0, 3);
			Player.FlagState fs = you.FlagStates.FirstOrDefault(fsOn => !fsOn.Touched);
			Point ptFlag = fs == null ? new Point(5, 6) : fs.Position;
			for (int turnOn = 0; turnOn < 40; turnOn++)
			{
				// pick 5 (or fewer if locked) random cards
				Card[] moveCards = new Card[5];
				bool [] cardUsed = new bool[cards.Length];
				for (int ind=0; ind<5-you.NumLockedCards; ind++)
					while (true)
					{
						int index = rand.Next(cards.Length);
						if (cardUsed[index]) 
							continue;
						moveCards[ind] = cards[index];
						cardUsed[index] = true;
						break;
					}

				// add in the locked cards
				for (int ind = 5 - you.NumLockedCards; ind < 5; ind++)
					moveCards[ind] = you.Cards[ind];

				// run it
				Utilities.MovePoint mp = Utilities.CardDestination(map, you.Robot.Location, moveCards);
				if (mp.Dead) 
					continue;

				// if better than before, use it
				int diff = Math.Abs(ptFlag.X - mp.Location.MapPosition.X) + Math.Abs(ptFlag.Y - mp.Location.MapPosition.Y);
				if (diff <= okDiff)
					return new PlayerTurn(moveCards, powerDown);
				if (diff < bestDiff)
				{
					bestDiff = diff;
					best = moveCards;
				}
			}

			return new PlayerTurn(best, powerDown);
		}
	}
}
